﻿#region Copyright(C) 2013-2013 FI Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME      : FI.Net Application Framework
// COMPONENT ID     : FI.Core.EntLib
// COMPONENT DESC   : Microsoft Enterprise Library Adapter.
//
// CREATED DATE/BY  : 18 Aug 2018 / Tian Mi
//
// REVISION HISTORY :
// DATE/BY            SR#/CS/PM#/OTHERS       DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using System.Collections.Generic;
using System.Linq;
using FI.Core.Utilities;

namespace FI.Core.Caching
{
    /// <summary>
    /// This static class maintain all keys of cache item added by all cache stores.
    /// </summary>
    public static class Keys
    {
        #region Fields
        private static readonly object syncHelper = new object();
        private static readonly Dictionary<string, List<string>> keys = new Dictionary<string, List<string>>();
        #endregion

        #region Public Methods
        /// <summary>
        /// Determines whether [contains] [the specified prefix].
        /// </summary>
        /// <param name="prefix">The prefix.</param>
        /// <returns>
        ///   <c>true</c> if [contains] [the specified prefix]; otherwise, <c>false</c>.
        /// </returns>
        public static bool Contains(string prefix)
        {
            Guard.ArgumentNotNullOrEmpty(prefix, "prefix");
            return keys.ContainsKey(prefix);
        }

        /// <summary>
        /// Adds a new key of cache item.
        /// </summary>
        /// <param name="prefix">The prefix of the cache item key.</param>
        /// <param name="key">The key of cache item.</param>
        public static void Add(string prefix, string key)
        {
            Guard.ArgumentNotNullOrEmpty(prefix, "prefix");
            Guard.ArgumentNotNullOrEmpty(key, "key");

            lock (syncHelper)
            {
                List<string> list;
                if (keys.TryGetValue(prefix, out list))
                {
                    if (!list.Contains(key))
                    {
                        list.Add(key);
                    }
                }
                else
                {
                    list = new List<string> { key };
                    keys.Add(prefix, list);
                }
            }
        }

        /// <summary>
        /// Removes the key of cache item.
        /// </summary>
        /// <param name="prefix">The prefix of the cache item key.</param>
        /// <param name="key">The key of cache item.</param>
        public static void Remove(string prefix, string key)
        {
            Guard.ArgumentNotNullOrEmpty(prefix, "prefix");
            Guard.ArgumentNotNullOrEmpty(key, "key");

            List<string> list;
            if (keys.TryGetValue(prefix, out list))
            {
                lock (syncHelper)
                {
                    if (list.Contains(key))
                    {
                        list.Remove(key);
                    }
                    if (!list.Any())
                    {
                        keys.Remove(prefix);
                    }
                }
            }
        }

        /// <summary>
        /// Clears the keys with the specified prefix.
        /// </summary>
        /// <param name="prefix">The prefix of the cache item key.</param>
        public static void Clear(string prefix)
        {
            Guard.ArgumentNotNullOrEmpty(prefix, "prefix");
            if (keys.ContainsKey(prefix))
            {
                lock (syncHelper)
                {
                    if (keys.ContainsKey(prefix))
                    {
                        keys.Remove(prefix);
                    }
                }
            }
        }

        /// <summary>
        /// Gets the all keys with the specified prefix.
        /// </summary>
        /// <param name="prefix">The prefix of the cache item key.</param>
        /// <returns>All keys with the specified prefix.</returns>
        public static IEnumerable<string> GetKeys(string prefix)
        {
            Guard.ArgumentNotNullOrEmpty(prefix, "prefix");
            List<string> list;
            if (keys.TryGetValue(prefix, out list))
            {
                return list;
            }
            return Enumerable.Empty<string>();
        }
        #endregion
    }
}